home *** CD-ROM | disk | FTP | other *** search
- Subject: v15i010: UUCP/CU access on one modem
- Newsgroups: comp.sources.unix
- Approved: rsalz@uunet.UU.NET
-
- Submitted-by: Dave Settle <No net address>
- Posting-number: Volume 15, Issue 10
- Archive-name: ultrix-modem
-
- [ Seems oriented toward System V-oid machines... --r$ ]
-
- I'm submitting the new version of 'modem', a program
- to allow a line connected to a modem to be used for bi-directional
- uucp/cu accesses.
-
- It functionally replaces 'uugetty', but provides a more sophisticated
- method of talking to intelligent modems, which can screw up uugetty by
- talking too much.
-
- The new version now has support for hardware DCD detection, which
- allows the shell to be hungup when the line is dropped.
-
- Cheers,
- Dave.
-
- #! /bin/sh
- # This is a shell archive, meaning:
- # 1. Remove everything above the #! /bin/sh line.
- # 2. Save the resulting text in a file.
- # 3. Execute the file with /bin/sh (not csh) to create:
- # README
- # modem.1
- # Makefile
- # modem.h
- # modem.c
- # uchange.c
- # sendex.c
- # io.c
- # line.c
- # statelook.c
- export PATH; PATH=/bin:/usr/bin:$PATH
- echo shar: "extracting 'README'" '(2276 characters)'
- if test -f 'README'
- then
- echo shar: "will not over-write existing file 'README'"
- else
- cat << \SHAR_EOF > 'README'
- Modem: A bi-directional uugetty replacement.
-
- "Modem" works just like "uugetty", and allows incoming and outgoing calls
- through the same port.
-
- In addition, it allows provides additional facilities:
-
- 1/. Option to insert a uucp-style send-expect conversation to
- initialise the modem.
-
- 2/. Code to spawn getty at the correct speed, if you have a modem that
- can sense the speed of incoming calls.
-
- 3/. Autologout facility, if there is no activity on the modem for
- a specified period of time.
-
- 4/. Log of all connected calls.
-
- 5/. Option to run "who" and "ps" on the port, when connected,
- if you're really security-concious.
-
- 6/. Correct handling of DCD (carrier detect) signals from the modem.
-
- 7/. Works happily with "uucp", "cu", and "kermit", which are not aware
- that "modem" is running. [NB Slight change necessary to uucp dialer script
- required]
-
- 8/. State-changing code, which allows you to set the modem in a state
- related to the time of day. Useful if you want it only to auto-answer
- when you're not there, and want to use it as a telephone otherwise.
- [Thanks to jack@swlabs.uucp for this code.]
-
-
- It works fine on my modem, which talks too much for uugetty to be able to
- handle it!
-
-
- For your local site, you have to do the following:
-
- Put this line in /etc/inittab
- XX:2:respawn:/usr/lib/modem ttyXX where ttyXX is your modem line
-
- Make sure that your dialer script is prepared to:
-
- a) sleep for > 1 sec BEFORE reading the first reply from the modem
- b) accept that the first character sent by the modem will NOT get there
-
- e.g. My Hayes dialer script is NORMALLY
-
- ... AT OK ATDP\T CONNECT
-
- but MUST be modified to
-
- ... AT\r\D OK ATDP\T CONNECT #( \D is a 2-sec pause )
-
-
- Modify the included dialer script to talk to YOUR modem, if you have a non-
- supported modem type. Please let me have your scripts, so that I can include
- them in future releases.
-
- Modify the speed-detection routine, if your modem is not a hayes-compatible
-
- Modify "locked()" to read YOUR lock directory - but see the makefile options
- for various lockfile protocols.
-
- If necessary, modify the wiring to the modem so that DCD is asserted
- when the modem is online, but not asserted at other times. This is
- necessary for the modem to generate a hangup signal when a remote site
- disconnects.
-
- SHAR_EOF
- if test 2276 -ne "`wc -c < 'README'`"
- then
- echo shar: "error transmitting 'README'" '(should have been 2276 characters)'
- fi
- fi
- echo shar: "extracting 'modem.1'" '(2065 characters)'
- if test -f 'modem.1'
- then
- echo shar: "will not over-write existing file 'modem.1'"
- else
- cat << \SHAR_EOF > 'modem.1'
- .TH modem 1 local
- .SH NAME
- modem
- .SH SYNOPSIS
- .B "modem [speed] tty"
- .PP
- .SH DESCRIPTION
- .I modem
- is a functional replacement for \fIuugetty\fR, and allows a line connected
- to a modem to be used for both incoming and outgoing uucp/cu calls.
- .PP
- It has an initial conversation with the modem, so that it can be set
- in the correct mode, and then waits for the modem to detect an incoming
- call. It then spawns \fIgetty(8)\fR to login the user, after making an
- alteration in the file /etc/utmp, so that getty thinks it was spawned by
- \fIinit(8)\fR.
- .PP
- While the user remains logged on, \fImodem\rB will periodically run
- \fIps\fR on the line, so that it can record what the user is doing.
- This facility can be turned off (see WATCHIT) option, if not required.
- .PP
- If, at any point prior to the incoming call, \fImodem\fR detects an
- \fBoutgoing\fR call, then it exits. Just before the exit, it attempts
- to set the line so that it can be used by outgoing callers.
- .PP
- If \fImodem\fR detects a LOCK file when it is invoked, then it will
- wait until this file is removed before proceeding.
- .PP
- \fImodem\fR also enforces an idle timeout, so that it the line appears
- to be idle for too long, the user is logged out. This may cause problems
- with kermit, which doesn't update the times on the device, but uses
- \fI/dev/tty\fR instead.
- .PP
- The optional \fBspeed\fR argument can be used to force \fImodem\fR to talk
- to the modem at the specified speed, otherwise it will talk at 1200 baud.
- .PP
- The tty name should be of the form \fBtty44\fR.
- .SH EXAMPLES
- .PP
- 44:2:respawn:/usr/lib/modem tty44
- .PP
- 1a:234:respawn:/usr/lib/modem 2400 tty1a
- .PP
- .SH FILES
- /dev/\fI<tty>\fB
- .PP
- /usr/spool/uucp/modem.log
- .SH SEE ALSO
- getty(8), uugetty(8), sh(1), ps(1), who(1), utmp(4)
- .SH BUGS
- The code for hardware DCD detection support is new.
- .PP
- There are still some unexplained diagnostics in my log file, mainly about
- write(1) calls failing to write characters.
- .PP
- You will have to modify some source code if your modem and/or system is
- different from mine (speed configuration and lock files).
- SHAR_EOF
- if test 2065 -ne "`wc -c < 'modem.1'`"
- then
- echo shar: "error transmitting 'modem.1'" '(should have been 2065 characters)'
- fi
- fi
- echo shar: "extracting 'Makefile'" '(1328 characters)'
- if test -f 'Makefile'
- then
- echo shar: "will not over-write existing file 'Makefile'"
- else
- cat << \SHAR_EOF > 'Makefile'
- #
- # new makefile for modem.
- #
- # if your lockfile is:
- # /usr/spool/uucp/LCK..<system> No defines needed.
- # /usr/spool/locks/LCK..<system> -DOL3B2
- # /usr/spool/locks/LCK.L.<system> -DHDB
- #
- # New definitions:
- # HDB: If you have Honey-Danber UUCP (Thanks Rick)
- # OL3B2: If you have an Olivetti 3B2
- # SPEEDCONFIG: If you have a modem that tells you the speed of incoming
- # calls (In ASCII - 300(or \r), 1200, 2400, 1275, 7512)
- # If your modem says different things, hack the code
- # WATCHIT: If you want "who" and "ps" run periodically to check
- # what's going on.
- # HAYES If you have a Hayes-type modem.
- # JSET: If you have an AT&T Aztec modem (Thanks Rick).
- # DEBUG: See what's going on.
- # SLOW: Wait 1 sec between each character written to the modem.
- # STATES If you want to use Jack's state-changing stuff.
- #
- # check "modem.h" for additional options on default modem speed and timezone.
- #
- CFLAGS = -DOL3B2 -DSPEEDCONFIG -DWATCHIT -DHAYES
- PARTS = modem.o uchange.o sendex.o io.o line.o statelook.o
- # LIBS = -lg
-
- modem: ${PARTS}
- rm -f modem
- cc ${PARTS} -o modem ${LIBS}
-
- install: modem
- mv /etc/modem /etc/modem.old
- cp modem /etc
-
- lint:
- lint ${CFLAGS} ${PARTS:.o=.c}
-
- ${PARTS}: modem.h Makefile
-
- shar:
- shar -cv README modem.1 Makefile modem.h ${PARTS:.o=.c} > modem.shar
-
-
- man:
- nroff -man modem.1 > modem.man
- SHAR_EOF
- if test 1328 -ne "`wc -c < 'Makefile'`"
- then
- echo shar: "error transmitting 'Makefile'" '(should have been 1328 characters)'
- fi
- fi
- echo shar: "extracting 'modem.h'" '(2898 characters)'
- if test -f 'modem.h'
- then
- echo shar: "will not over-write existing file 'modem.h'"
- else
- cat << \SHAR_EOF > 'modem.h'
- /*
- * some constants for your modem
- */
-
- #define TIMEZONE "TZ=GMT0BST" /* time zone you operate in */
- #define DEFSPEED "1200" /* speed your modem likes most */
-
- #define WTIME 5 /* default wait time */
-
- #define LOGFILE "/usr/spool/uucp/modem.log" /* log file */
-
- #define max(a,b) ((a) > (b) ? (a) : (b))
- #define min(a,b) ((a) < (b) ? (a) : (b))
-
- #define MINUTES 60
- #define IDLETIME 5*MINUTES /* autologout time */
- #ifdef WATCHIT
- #define SPYTIME 1*MINUTES
- #else
- #define SPYTIME IDLETIME
- #endif
-
- #define GRACETIME 5 /* time to wait for signal to take effect */
-
- extern int errno;
-
- #ifdef MAINDEF
- #define EXTERN
- #else
- #define EXTERN extern
- #endif
-
- long time();
- int dread(), dwrite(), myread();
- void mywrite();
-
- EXTERN char lockf[50]; /* argument lock file */
- EXTERN char dname[30]; /* device name in full - /dev/.... */
-
- EXTERN int shell, status; /* pid of shell, and exit status */
-
- EXTERN int dev; /* device used (open fildes) */
- /*
- * The 'reset' sequence, if the modem doesn't behave as expected.
- * I still get problems with the modem not responding to 'AT'.
- */
- #if defined(HAYES)
- #define RESET "\n\rAT\r\rAT\r\rAT\r\r"
- #else
- #define RESET ""
- #endif
- /*
- * The 'conversation' necessary to get your modem into a 'listening' state.
- * The converasation should complete iff an incoming call is connected.
- * If using Jack's states, set up your states below. Each modem line
- * must have flags set to indicate in which state(s) it can be executed.
- * If you're not using the STATES stuff, leave them at zero.
- */
- #define SPK 0x0001 /* Speaker control */
- #define AA 0x0002 /* Auto Answer Control */
-
- struct conv {
- char *c_send;
- char *c_expect;
- int c_wait; /* time to wait for c_expect */
- int c_flags; /* flags for matching with the state. */
- };
-
- #ifdef MAINDEF
-
- struct conv ring[] = {
-
- #if defined(HAYES)
- {"AT\r", "OK", WTIME, AA | SPK }, /* anyone there? */
- {"ATM0\r", "OK", WTIME, AA | SPK }, /* turn OFF speaker */
- {"ATS0=0\r", "OK", WTIME, AA | SPK}, /* DISABLE auto-answer */
- {"ATS0=1\r", "OK", WTIME, AA}, /* maybe enable auto answer */
- {"ATM1\r", "OK", WTIME, SPK}, /* maybe turn speaker on */
- {"ATX1V1\r", "OK", WTIME, AA | SPK }, /* turn on responses */
- {"ATS24=3\r", "OK", WTIME, AA | SPK}, /* enable speed-seeking */
- {"", "RING", 0, AA | SPK}, /* wait (indefinately) for RING in */
- {"", "CONNECT", 20, AA | SPK}, /* wait for call to be connected */
- {NULL, NULL, 0, 0} /* finished */
-
- #else /* defined (HAYES) */
- #if defined(JSET) /* AT&T Aztec Protocol */
- {"\\d\r\\d", "MODEM: ", WTIME, 0 }, /* anyone there? */
- {"", "DATA", 3600, 0}, /* wait (1 hour) for RING in */
- {NULL, NULL, 0, 0} /* Should be indefinite, but prevent
- problems if modem gets wedged */
-
- #else /* defined (JSET) */
- {NULL, NULL, 0, 0} /* no init conversation */
-
- #endif /* defined (JSET) */
- #endif /* defined (HAYES) */
- };
- #endif /* defined (MAINDEF) */
- SHAR_EOF
- if test 2898 -ne "`wc -c < 'modem.h'`"
- then
- echo shar: "error transmitting 'modem.h'" '(should have been 2898 characters)'
- fi
- fi
- echo shar: "extracting 'modem.c'" '(10194 characters)'
- if test -f 'modem.c'
- then
- echo shar: "will not over-write existing file 'modem.c'"
- else
- cat << \SHAR_EOF > 'modem.c'
- /*
- * Copyright (c) Dave Settle 1987
- * All rights reserved.
- * Permission is granted to do anything with this program, except remove
- * this copyright notice, or sell it for profit.
- *
- * Problems, suggestions, bug fixes etc, to:
- *
- * Dave Settle, SMB Business Software, Thorn EMI Datasolve
- *
- * UUCP:
- * dave@smb.co.uk
- * ...!mcvax!ukc!nott-cs!smb!dave
- *
- * SMAIL: Voice:
- * SMB Business Software +44 623 651651
- * High Street
- * Mansfield Telex:
- * Nottingham NG18 1ES 37392 TECSMG
- * England
- * Fax:
- * +44 623 659947
- *
- * modem.c: a bi-directional "getty" to allow incoming calls AND outgoing
- * uucico's
- *
- * Modified by Rick Richardson for HDB uucp and AT&T Aztec protocol
- *
- * Modified by Jack Bonn for state logic (allows autoanswer on/off at
- * a given time for each day of the week)
- *
- * Modified by Dave Settle:
- *
- * Code fixes:
- * hangup routine added, to make sure phone is down before script, and
- * after user disconnects.
- * Parameterised send-expect routines.
- * Minor bug fix to dread()
- * Re-enable SIGALRM in wakeup()
- * Catch all signals, to enable crashes to be detected.
- * Chmod device back to 666, so that we can use it afterwards.
- * Oct 87: fixup modem control with CLOCAL, so that remote disconnect
- * can be detected and dealt with.
- * Oct 87: fix autologout to send series of signals, not just SIGHUP
- * Oct 87: Clean up code, and distribute to other source files.
- * Nov 87: Fix lurking bug in 'expect'. Clean code for 'lint'.
- * Nov 87: Ignore SIHGUP's generated by 'hangup'.
- * Dec 87: Force getty NOT to hangup the line before login.
- * Jan 87: Open stdio file descriptors.
- *
- *
- */
- #include <sys/types.h>
- #include <stdio.h>
- #include <signal.h>
- #include <errno.h>
- #include <fcntl.h>
- #include <termio.h>
- #include <sys/stat.h>
- #include <time.h>
-
- #ifdef WATCHIT
- #include <pwd.h>
- struct passwd *getpwuid();
- #endif
-
- #define MAINDEF
- #include "modem.h" /* variable definitions */
- /*
- * wakeup gets called when the alarm goes off
- */
- wakeup(){
- signal(SIGALRM, wakeup);
- }
-
- fault(sig){
- printf("Crashed with signal %d\n", sig);
- closedown(sig);
- }
-
- closedown(sig){
- time_t now;
- now = time((long *) 0);
- /*
- * [Nov 87]: Since we're about to hang up the phone,
- * ignore the signal that this is going to generate.
- */
- signal(SIGHUP, SIG_IGN);
- if(sig) printf("Caught signal %d\n", sig);
- printf("Closedown at %s", asctime(localtime(&now)));
- /*
- * Oct 87: new addition for SIGHUP. We receive this signal when the line
- * is disconnected by a remote caller. Since the line is dead, so should
- * the shell be (it got SIGHUP same as us); log it out anyway, even if it's
- * trying to ignore it.
- */
- if((sig == SIGHUP) && shell) autologout(shell);
- /*
- * change the value in utmp back to our pid.
- */
- if(shell) uchange(shell, getpid()); /* back to normal */
- /*
- * clear modem line, which should also hangup the phone (if it wasn't already).
- */
- hangup(dev);
- close(dev);
- /*
- * chmod the device back to 666, so that uucico and cu can access it.
- * NOTE: I prefer this to chown(uucp), which does not allow "cu" access.
- */
- chmod(dname,0666); /* uucp access */
- unlink(lockf);
- if(status) printf("Logout status 0x%x\n", status);
- fclose(stdout);
- exit(0);
- }
-
- main(argc, argv, envp)
- char **argv, **envp;
- {
- long t;
- char *arg[5], *speed;
- int baud, i;
- struct conv *p;
- struct stat sbuf;
- time_t now, mtime;
- #ifdef WATCHIT
- FILE *procs;
- struct passwd *pw;
- char psbuff[128];
- #endif
- #ifdef SPEEDCONFIG
- char c, buff[8];
- #endif
- #ifdef STATES
- time_t delta, suicide;
- int state;
- #endif
- FILE *lock;
- /*
- * catch and report all signals, but apply special treatment to legal signals
- * Any program bugs get reported this way. You can get a core dump by sending
- * it SIGFPE.
- */
- for(i=1;i<SIGUSR1;i++) signal(i, fault);
-
- signal(SIGHUP, SIG_IGN);
- signal(SIGINT, SIG_IGN);
- signal(SIGQUIT, SIG_IGN);
- signal(SIGFPE, SIG_DFL); /* you can get a core dump here */
- signal(SIGALRM, wakeup);
- signal(SIGTERM, closedown);
- /*
- * Open the standard I/O file descriptors, if not already open.
- * Running from init, we don't have a terminal, so output to LOGFILE.
- */
- if((i = open("/dev/null", 0)) == 0) {
- open("/dev/null", 1);
- open("/dev/null", 1);
- }
- else close(i);
- freopen(LOGFILE, "a", stdout);
- #ifdef SETBUF
- setbuf(stdout, NULL); /* if setvbuf broken */
- #else
- setvbuf(stdout, NULL, _IOLBF, 0);
- #endif
-
- if (argc < 2)
- {
- printf("Usage: %s <tty> [<speed>]\n", argv[0]);
- sleep(5);
- exit(5);
- }
-
- sprintf(dname, "/dev/%s", argv[1]);
- #if defined(OL3B2)
- sprintf(lockf, "/usr/spool/locks/LCK..%s", argv[1]);
- #else
- #if defined(HDB)
- sprintf(lockf, "/usr/spool/locks/LCK.L.%s", argv[1]);
- #else
- sprintf(lockf, "/usr/spool/uucp/LCK..%s", argv[1]);
- #endif
- #endif
- /*
- * do not start while device is locked
- */
- while(locked()) sleep(30);
- if((dev = open(dname, O_RDWR | O_NDELAY)) == -1) {
- perror(dname);
- sleep(5); /* don't go crazy with respawns */
- exit(4);
- }
-
- /*
- * setup correct time zone
- */
- putenv(TIMEZONE);
- /*
- * set terminal parameters
- * Additional argument (if present) can be used to force an initial speed
- * (Thanks rick)
- */
- if(argc > 2) speed = argv[2];
- else speed = DEFSPEED;
- baud = findspeed(speed);
- init_term(dev, baud);
- /*
- * send-expect strings - at the end, someone has connected to the modem
- */
- #ifdef STATES
- /*
- * find out when the next state change is due to occur. At this point, we exit.
- * The next initiation will set the modem up differently.
- */
- delta = duration(&state);
- suicide = time((long *) 0) + delta;
- #endif
- for(p = ring; p->c_send; p++) {
- #ifdef STATES
- if(!applicable(p, state)) continue;
- #endif
- send(p->c_send, mywrite);
- #ifdef STATES
- if(expect(p->c_expect, (int)(p->c_wait ? min(p->c_wait, delta) : delta), myread)) {
- #else
- if(expect(p->c_expect, p->c_wait, myread)) {
- #endif
- t = time((long *) 0);
- #ifdef STATES
- if(t >= suicide) {
- printf("Exit due to state change\n");
- exit(0);
- }
- #endif
- printf("Incoming call failed to connect on %s", asctime(localtime(&t)));
- /*
- * we don't have to do anything special here, since no locks have been setup.
- * However, since the main problems appear to be non-responding modems, send
- * it some sort of 'un-wedging' sequence
- */
- send(RESET, mywrite);
- sleep(3);
- hangup(dev);
- sleep(10);
- ioctl(dev, TCFLSH, 2); /* Flush both queues */
- exit(3);
- /*NOTREACHED*/
- }
- }
- signal(SIGALRM, wakeup);
- /*
- * OK - incoming call connected. Find speed (if possible), create lock file,
- * then spawn getty.
- * At this point, we also trap hangups, so that we can clean up after
- * any incoming calls. (Hangups are now detected by the hardware).
- */
- signal(SIGHUP, closedown);
- #ifdef SPEEDCONFIG
- dread(dev, &c, 1);
- if(c == '\r') speed = "300";
- else {
- dread(dev, buff, 4);
- if(!strcmp(buff, "1200")) speed = "1200";
- if(!strcmp(buff, "2400")) speed = "2400";
- if(!strcmp(buff, "1275")) speed = "1200";
- if(!strcmp(buff, "7512")) speed = "1200";
- }
- baud = findspeed(speed);
- #endif
-
- t = time((long *)0);
- printf("Call connected at %s on %s", speed, asctime(localtime(&t)));
- /*
- * Someone has rung in - lock the device.
- */
- lock = fopen(lockf, "w");
- /*
- * hand over to "getty"
- */
- arg[0] = "getty";
- arg[1] = "-h";
- arg[2] = argv[1];
- arg[3] = speed;
- arg[4] = NULL;
-
- if(shell = fork()) {
- /*
- * change the utmp pid to the "getty" process, so that it can login
- */
- uchange(getpid(), shell); /* change utmp entry */
- #if defined(OL3B2)
- fprintf(lock," %d\n", shell);
- #else
- #if defined(HDB)
- fprintf(lock,"%d\n", shell);
- #else
- fwrite((char *) &shell, sizeof shell, 1, lock);
- #endif
- #endif
- fclose(lock);
- /*
- * wait for logout from shell.
- * if terminal is idle for IDLETIME, force a logout anyway
- */
- alarm(SPYTIME);
- while((wait(&status) == -1) && (errno == EINTR)) {
- if(stat(dname, &sbuf) == -1) {
- perror(dname);
- continue;
- }
- now = time((long *)0);
- mtime = max(sbuf.st_atime, sbuf.st_mtime);
-
- if((now - mtime) >= IDLETIME) {
- write(dev, "autologout\r\n", 12);
- printf("Device idle - autologout at %s\n",
- asctime(localtime(&now)));
- uchange(shell, getpid());
- autologout(shell);
- break;
- }
-
- #ifdef WATCHIT
- t = time((long *) 0);
- pw = getpwuid((int) sbuf.st_uid);
- printf("Logon user is %s on %s", pw->pw_name,
- asctime(localtime(&t)));
- procs = popen("ps -ef", "r");
- while(fgets(psbuff, sizeof psbuff, procs))
- if(partof(psbuff, argv[1]) && partof(psbuff, pw->pw_name))
- printf("%s", psbuff);
- pclose(procs);
- #endif
- alarm(SPYTIME);
- }
- t = time((long *) 0);
- printf("Call disconnected on %s", asctime(localtime(&t)));
- closedown(0); /* remove locks etc */
- /*NOTREACHED*/
- }
- else {
- sleep(1); /* allow changes to utmp */
- /*
- * Re-do the termio settings, so that we can login.
- * CLOCAL is removed at this point, so that a hangup will generate SIGHUP.
- * Close all the files which we have open - getty expects none.
- */
- login_term(dev, baud);
- for(i=0;i<20;i++) close(i);
- #ifdef DEBUG
- printf("%d: /etc/getty %s %s\n", getpid(), arg[1], arg[2]);
- #endif
- execve("/etc/getty", arg, envp);
- printf("can't exec getty\n");
- exit(1);
- /* NOTREACHED */
- }
- }
- /*
- * check for presence of lock file
- * return 1 if locked.
- */
- locked(){
- struct stat sb;
- if(stat(lockf, &sb) == -1) return(0);
- #ifdef DEBUG
- printf("%s locked\n", lockf);
- #endif
- return(1);
- }
- #ifdef WATCHIT
- /*
- * partof: look for str in text. Has a bug if you look for ...xxx...
- */
- partof(text, str)
- char *text, *str;
- {
- char *needle, *p;
- for(p = text, needle = str; *p ; p++) {
- if(*p != *needle) needle = str;
- if(*p == *needle) needle++;
- if(*needle == '\0') return(1);
- }
- return(0);
- }
- #endif
- /*
- * autologout: log out the child shell. Sends SIGHUP, SIGTERM, SIGKILL
- * until the child exits.
- */
- autologout(child)
- {
- kill(child, SIGHUP);
- alarm(GRACETIME);
- if(wait(&status) == -1) {
- kill(child, SIGTERM);
- alarm(GRACETIME);
- if(wait(&status) == -1) {
- kill(child, SIGKILL);
- alarm(GRACETIME);
- if(wait(&status) == -1) {
- printf("Cannot kill child pid %d\n", child);
- status = 0;
- }
- }
- }
- alarm(0);
- }
- SHAR_EOF
- if test 10194 -ne "`wc -c < 'modem.c'`"
- then
- echo shar: "error transmitting 'modem.c'" '(should have been 10194 characters)'
- fi
- fi
- echo shar: "extracting 'uchange.c'" '(711 characters)'
- if test -f 'uchange.c'
- then
- echo shar: "will not over-write existing file 'uchange.c'"
- else
- cat << \SHAR_EOF > 'uchange.c'
- /*
- * Copyright (c) Dave Settle, Mar 1987
- * Permission is granted to do anything with this program, except remove
- * this copyright notice, or sell it for profit.
- *
- *
- * change the ut_pid value from "old" to "new".
- * Attempts to do all the things that "getty" appears to do.
- */
-
- #include <sys/types.h>
- #include <utmp.h>
-
- struct utmp *utmp, *getutent();
-
- uchange(old, new)
- {
- setutent();
- while(utmp = getutent()) {
- if(utmp->ut_pid == old) {
- utmp->ut_pid = new;
- if(strcmp(utmp->ut_user, "getty"))
- strcpy(utmp->ut_user, "modem");
- else
- strcpy(utmp->ut_user, "getty");
- pututline(utmp);
- endutent();
- return(1);
- }
- }
- printf("Can't find utmp entry\n");
- endutent();
- return(1);
- }
-
- SHAR_EOF
- if test 711 -ne "`wc -c < 'uchange.c'`"
- then
- echo shar: "error transmitting 'uchange.c'" '(should have been 711 characters)'
- fi
- fi
- echo shar: "extracting 'sendex.c'" '(1797 characters)'
- if test -f 'sendex.c'
- then
- echo shar: "will not over-write existing file 'sendex.c'"
- else
- cat << \SHAR_EOF > 'sendex.c'
- /*
- * Copyright (c) Dave Settle, Mar 1987
- * Permission is granted to do anything with this program, except remove
- * this copyright notice, or sell it for profit.
- *
- *
- * sendex.c: contains the send-expect routines, beefed-up a little to
- * make them more useful.
- * Both "send" and "expect" now have a function, rather than
- * a file descriptor. This function gets called as follows:
- *
- * (int) (*rdfunc)(); [send]
- * (*wtfunc)((char *)s); [expect]
- *
- */
-
- #include <setjmp.h>
- #include <signal.h>
- #include <stdio.h>
- /*
- * send: write the string out. Show the chars written if necessary.
- */
- send(s, func)
- char *s;
- void (*func)();
- {
- #ifdef DEBUG
- printf("send(");
- sshow(s);
- printf(")\n");
- #endif
- (*func)(s);
- sleep(1);
- }
- /*
- * expect: expect a string. Return 0 on success, 1 on timeout.
- * chars are threaded on the needle as they match the expect string
- * if one fails to match, all chars are unthreaded.
- * expect succeeds if all chars on expect string are threaded.
- */
- jmp_buf env;
-
- timeout(){
- longjmp(env, 1);
- }
-
- expect(s, t, func)
- char *s;
- int (*func)();
- {
- char *needle = s, c;
- int (*handler)();
- alarm(0);
- handler = signal(SIGALRM, timeout);
- if(setjmp(env)) {
- printf("Timeout expecting %s\n", s);
- return(1); /* fail - timeout */
- }
- alarm(t); /* if zero, no timeout */
- #ifdef DEBUG
- printf("\nexpect(%s)\n", s);
- #endif
- while(*needle) {
- c = (*func)();
- #ifdef DEBUG
- show(c);
- #endif
- if(*needle != c) needle = s;
- if(*needle == c) needle++;
- }
- #ifdef DEBUG
- printf("got it\n");
- #endif
- alarm(0);
- signal(SIGALRM, handler);
- return(0);
- }
- #ifdef DEBUG
- /*
- * sshow: show string
- */
- sshow(s)
- char *s;
- {
- while(*s) show(*s++);
- }
- show(c)
- char c;
- {
- if((c < 31)) {
- printf("^%c", c + '@');
- if(c == '\n') putchar('\n');
- }
- else putchar(c);
- fflush(stdout);
- }
- #endif
-
- SHAR_EOF
- if test 1797 -ne "`wc -c < 'sendex.c'`"
- then
- echo shar: "error transmitting 'sendex.c'" '(should have been 1797 characters)'
- fi
- fi
- echo shar: "extracting 'io.c'" '(4690 characters)'
- if test -f 'io.c'
- then
- echo shar: "will not over-write existing file 'io.c'"
- else
- cat << \SHAR_EOF > 'io.c'
- /*
- * Copyright (c) Dave Settle, March 1987
- * Permission is granted to do anything with this program, except remove
- * this copyright notice, or sell it for profit.
- *
- *
- * io.c: routines to talk to the device directly.
- *
- * dread and dwrite act like read(2) and write(2), execpt that they always
- * either succeed or exit, so the caller doesn't have to check.
- *
- * hangup drops the DTR line to the modem, so that it will (hopefully) hang up
- * the phone line. It keeps it this way for 5 seconds.
- *
- * findspeed takes an ascii speed, and returns the corresponing baud rate.
- *
- * uuexit is a dodgy routine to make UUCP happy.
- */
-
- #include <sys/errno.h>
- #include <termio.h>
- #include <fcntl.h>
-
- #include "modem.h"
-
- char *sys_errlist[]; /* error list */
- #define RETRY 5 /* retry failed writes */
- /*
- * dwrite: write some characters to the modem.
- * If your modem likes characters to be written s-l-o-w-l-y, define 'SLOW'
- */
- dwrite(f, s, n)
- int f;
- unsigned n;
- char *s;
- {
- struct termio termio;
- int r, retry = 0, i = 0;
- static int error = 0; /* error occurred on last call */
- while((i < n) && (retry < RETRY)) {
- if(locked()) uuexit(0);
- errno = 0;
- if(r = write(f, s + i, 1) == 1) i++; /* Success! */
- else {
- retry++;
- fixline();
- }
- #ifdef SLOW
- sleep(1); /* Let the modem deal with it */
- #endif
- }
- if(i != n) {
- ioctl(dev, TCGETA, &termio);
- printf("Tried %d times, still got %d/%d written. [error = %s]\n",
- retry, i, n, sys_errlist[errno]);
- printf("FAIL: dev %d, iflag %x, oflag %x, cflag %x, lflag %x, line %d\n",
- dev, termio.c_iflag,termio.c_oflag,termio.c_cflag,
- termio.c_lflag, termio.c_line);
- error = 1;
- }
- else if(retry > 1) printf("Write problem: fixed on retry %d\n", retry - 1);
- if(error && i == n) {
- ioctl(dev, TCGETA, &termio);
- printf("OK: iflag %x, oflag %x, cflag %x, lflag %x, line %d\n",
- termio.c_iflag,termio.c_oflag,termio.c_cflag,
- termio.c_lflag, termio.c_line);
- }
- if(i == n) error = 0;
- return(r);
- }
- /*
- * read one character at a time, checking before (and after) each read for
- * a lock file. If one exists, then exit.
- */
- dread(f, s, n)
- int f, n;
- char *s;
- {
- int i, w;
- for(i=0;i<n;i++, s++) {
- if(locked()) uuexit(0);
- while((w = read(f, s, 1)) < 1) {
- if(locked()) uuexit(0);
- if(w == -1) switch(errno) {
- case EINTR:
- break;
- default:
- perror("dread");
- }
- }
- }
- }
- /*
- * hangup(): hangup the phone, and close the device.
- * I've had problems with indefinate echoes from the modem when a connection
- * has closed - my modem transmits crap. This ought to hangup the phone and
- * prevent this.
- *
- * Oct 87: This problem should now be fixed, with the introduction of the
- * DCD control from the modem - we should now receive a hangup signal when
- * the line drops.
- */
- hangup(device) {
- struct termio term;
- if(ioctl(device, TCGETA, &term) == -1) perror("hangup: TCGETA");
- term.c_lflag &= ~(ECHO | ECHOE | ECHOK);
- term.c_cflag &= ~CBAUD;
- term.c_cflag |= B0; /* hangup */
- if(ioctl(device, TCSETA, &term) == -1) perror("hangup: TCSETA");
- if(ioctl(device, TCFLSH, 2) == -1) perror("hangup: TCFLSH");
- sleep(5); /* 5 seconds with DTR down */
- return(0);
- }
- /*
- * findspeed: convert ascii baud rate into termio parameter.
- */
- findspeed(s)
- char *s;
- {
- int baud = atoi(s);
- switch(baud) {
- case 110: baud = B110;
- break;
- case 300: baud = B300;
- break;
- case 1200: baud = B1200;
- break;
- case 2400: baud = B2400;
- break;
- default:
- printf("findspeed: unknown baud rate %s\n", s);
- baud = B1200;
- }
- return(baud);
- }
- /*
- * uuexit: make line useable by UUCP.
- * Because UUCP is pretty determined about using a "modem", it clears CLOCAL
- * which means that it can't write any characters at this point (modem not
- * online, so DCD not asserted). Not suprisingly, it doesn't work.
- * Solution: turn it on again, while UUCP isn't looking; this seems to work
- * fine, although I'm a little puzzled about the timing: this is a
- * definate "trial and error" solution.
- * This unfortunately also means that UUCP won't detect a line hangup,
- * so we have to rely on it's timeout facilities ...
- */
- #define DIALTIME 5 /* time to continue to assert CLOCAL */
- uuexit(code)
- {
- struct termio term;
- register int i;
- for(i=0;i<DIALTIME;i++) {
- close(open(dname, O_RDONLY | O_NDELAY)); /* vital magic */
- if(ioctl(dev, TCGETA, &term) == -1) perror("qx TCGETA");
- term.c_cflag |= CLOCAL;
- if(ioctl(dev, TCSETA, &term) == -1) perror("qx TCSETA");
- close(open(dname, O_RDONLY | O_NDELAY)); /* vital magic */
- sleep(1);
- }
- exit(code);
- }
- /*
- * extensions for send & expect
- */
- myread()
- {
- char c;
- dread(dev, &c, 1);
- return(c);
- }
- void mywrite(s)
- char *s;
- {
- dwrite(dev, s, strlen(s));
- }
-
- SHAR_EOF
- if test 4690 -ne "`wc -c < 'io.c'`"
- then
- echo shar: "error transmitting 'io.c'" '(should have been 4690 characters)'
- fi
- fi
- echo shar: "extracting 'line.c'" '(2338 characters)'
- if test -f 'line.c'
- then
- echo shar: "will not over-write existing file 'line.c'"
- else
- cat << \SHAR_EOF > 'line.c'
- /*
- * line.c: set up the various termio params for the line at various stages.
- * [What I would like for Christmas: System V tty driver code, so I could
- * find out why it behaves so strangely ... ]
- */
-
- #include "modem.h"
- #include <termio.h>
- #include <fcntl.h>
-
- static struct termio term;
- static int speed;
-
- init_term(device, baud)
- int device, baud;
- {
- speed = baud;
- if(ioctl(device, TCGETA, &term) == -1) perror("TCGETA");
- term.c_lflag &= ~(ICANON | ECHO | ECHOE | ECHOK);
- term.c_iflag &= ~(ISTRIP | INPCK);
- term.c_cflag &= ~(CBAUD | CSIZE);
- term.c_cflag |= baud | CS8 | CLOCAL;
- term.c_cc[VMIN] = 1;
- term.c_cc[VTIME] = 0;
- if(ioctl(device, TCSETA, &term) == -1) perror("TCSETA");
- /*
- * Since we opened the line with O_NDELAY, reads will return immediately if
- * no chars are ready. We don't really want this, 'cos "dread" will then
- * eat CPU time, so we turn it off.
- * It only seems to be really effective when the device is opened again -
- * otherwise we get strange diagnostics about "wrote 0 of 4". Thanks to
- * the C-KERMIT crew for this tip.
- *
- * The open() here seems to hang sometimes, so a timeout is implemented.
- * [since CLOCAL has been set above, this should never happen. We can't
- * just open with O_NDELAY, because uucp won't work anyway.]
- */
- fcntl(device, F_SETFL, 0);
- alarm(5);
- if(close(open(dname, O_RDONLY)) == -1 ) {
- printf("** Error: Couldn't reopen device after TCSETA\n");
- exit(1);
- }
- alarm(0);
- }
- /*
- * Strange things have been known to happen during "login" with incorrect
- * settings - if it forgets to ask you for a password, check them carefully.
- * Oct 87: Disable CLOCAL, since DCD is now asserted, and we want to be told
- * about hangups.
- */
- login_term(device, baud)
- int device, baud;
- {
- ioctl(device, TCGETA, &term);
- term.c_cc[VEOF] = 04; /* cntrl-D */
- term.c_iflag = BRKINT | IGNPAR | ISTRIP | ICRNL;
- term.c_oflag = OPOST | ONLCR | TAB3;
- term.c_cflag &= ~(CSIZE | CLOCAL | CBAUD);
- term.c_cflag |= CS7 | HUPCL | CREAD | baud;
- term.c_lflag = ISIG | ICANON;
- ioctl(device, TCSETAW, &term);
- }
- /*
- * fixline: write failed - redo settings on line.
- */
- fixline(){
- ioctl(dev, TCFLSH, 2); /* flush queues */
- ioctl(dev, TCXONC, 1); /* restart XON/XOFF */
- fcntl(dev, F_SETFL, 0); /* poke the flag */
- close(open(dname, O_RDONLY | O_NDELAY));
- init_term(dev, speed);
- }
-
- SHAR_EOF
- if test 2338 -ne "`wc -c < 'line.c'`"
- then
- echo shar: "error transmitting 'line.c'" '(should have been 2338 characters)'
- fi
- fi
- echo shar: "extracting 'statelook.c'" '(3302 characters)'
- if test -f 'statelook.c'
- then
- echo shar: "will not over-write existing file 'statelook.c'"
- else
- cat << \SHAR_EOF > 'statelook.c'
- /*
- * Stuff to work out when to next change state (causes exit)
- * and whether to apply a particular bit of the modem conversation.
- */
-
- #include <time.h>
-
- #include "modem.h"
- #ifdef STATES
-
- #define SECS_IN_WEEK (60L * 60L * 24L * 7L)
- #define WEEK_TIME(d,h,m) ((((long)d*24L+(long)h)*60L+(long)m)*60L)
- #define EVENT_LEN (sizeof(week_event)/sizeof(struct event))
- #define IND_LEN (sizeof(ind_tab)/sizeof(struct ind))
-
- /*
- This is a table of when to turn on and off the autoanswer mode
- of the modem.
- */
- struct event {
- long s_time;
- int s_state;
- } week_event[] = {
- { WEEK_TIME (0, 7, 35), AA | SPK }, /* AA on, speaker on 7:35 Sun */
- { WEEK_TIME (0, 22, 00), AA }, /* AA on, speaker off 22:00 Sun */
- { WEEK_TIME (1, 7, 35), SPK }, /* AA off, speaker on 7:35 Mon */
- { WEEK_TIME (1, 17, 25), AA | SPK }, /* AA on, speaker on 17:25 Mon */
- { WEEK_TIME (1, 22, 00), AA }, /* AA on, speaker off 22:00 Mon */
- { WEEK_TIME (2, 7, 35), SPK }, /* AA off, speaker on 7:35 Tue */
- { WEEK_TIME (2, 17, 25), AA | SPK }, /* AA on, speaker on 17:25 Tue */
- { WEEK_TIME (2, 22, 00), AA }, /* AA on, speaker off 22:00 Tue */
- { WEEK_TIME (3, 7, 35), SPK }, /* AA off, speaker on 7:35 Wed */
- { WEEK_TIME (3, 17, 25), AA | SPK }, /* AA on, speaker on 17:25 Wed */
- { WEEK_TIME (3, 22, 00), AA }, /* AA on, speaker off 22:00 Wed */
- { WEEK_TIME (4, 7, 35), SPK }, /* AA off, speaker on 7:35 Thu */
- { WEEK_TIME (4, 17, 25), AA | SPK }, /* AA on, speaker on 17:25 Thu */
- { WEEK_TIME (4, 22, 00), AA }, /* AA on, speaker off 22:00 Thu */
- { WEEK_TIME (5, 7, 35), SPK }, /* AA off, speaker on 7:35 Fri */
- { WEEK_TIME (5, 17, 25), AA | SPK }, /* AA on, speaker on 17:25 Fri */
- { WEEK_TIME (5, 22, 00), AA }, /* AA on, speaker off 22:00 Fri */
- { WEEK_TIME (6, 7, 35), AA | SPK }, /* AA on, speaker on 7:35 Sat */
- { WEEK_TIME (6, 22, 00), AA } /* AA on, speaker off 22:00 Sat */
- };
-
- long duration(state)
- int *state; /* 0 if new Auto Answer state is OFF, 1 if ON */
- {
- long secs_into_week; /* Seconds since midnight Sunday morning */
- long t;
- struct tm *cur_time;
- int i, index;
- long delta, tst_delta;
-
- t = time((long *) 0);
- cur_time = localtime (&t);
-
- secs_into_week = ((((long)(cur_time->tm_wday)) * 24L +
- (long)(cur_time->tm_hour)) * 60L +
- (long)(cur_time->tm_min)) * 60L +
- (long)(cur_time->tm_sec);
-
- delta = SECS_IN_WEEK + 1; /* SOMETHING has to be closer than this! */
-
- /* Loop looking for an entry with a better delta (closer to now) */
-
- for (i=0; i < EVENT_LEN; i++) {
- tst_delta = week_event[i].s_time - secs_into_week;
- if (tst_delta < 0L)
- tst_delta += SECS_IN_WEEK; /* Adjust for wrap around */
- if (tst_delta < delta) {
- /* We found a closer event to now */
- delta = tst_delta;
- index = i;
- }
- }
- /*
- * Decrement index by one circularly (note table MUST be in order) --
- */
- if (index-- == 0)
- index = EVENT_LEN-1;
- *state = week_event[index].s_state;
- #ifdef DEBUG
- printf("Currently in state %d. Will change in %ld seconds\n",
- *state, delta);
- #endif
- return(delta);
- }
-
- /*
- This routine decides whether a particular init line should be executed.
- */
- applicable(p, state)
- struct conv *p;
- int state;
- {
- return(p->c_flags & state);
- }
-
- #endif
- SHAR_EOF
- if test 3302 -ne "`wc -c < 'statelook.c'`"
- then
- echo shar: "error transmitting 'statelook.c'" '(should have been 3302 characters)'
- fi
- fi
- exit 0
- # End of shell archive
-
-
- --
-
- Dave Settle,
- SMB Business Software, Thorn EMI Datasolve, High St, Mansfield, UK
-
- UUCP: dave@smb.co.uk
- ...!mcvax!ukc!nott-cs!smb!dave
-
- <--- This way to point of view --->
-
-